package ServerDB;
import DataConnectionInterface.*;
import DatabaseManager.*;
import java.io.*;

import Helper.GameException;
import java.net.*;

public class Server {

	private Thread[] threads = new Thread[2];
	private ServerSocket serverSocket = null;
	public static int portNumber = 3000;
	public static int numCards;
	private GameState gameState = new GameState();
	private NotifyMonitor monitor = new NotifyMonitor();
	private int numOfConnections = 0;
	private boolean isConnected[] = new boolean[2];
	private ConnectionPool connPool;
	
	private void waitForDisconnection() {
		boolean disconnect = false;
		int disconnections = 0;
		while (true) {
			for (int i = 0; i < 2; i++) {
				switch (monitor.getNotified(i)) {
				case QUIT:
					// game was finished successfully
					disconnections++;
					numOfConnections--;
					isConnected[i] = false;
					monitor.setNotified(i, DisconnectionType.NONE);
					threads[i] = null;
					
					boolean hasWon = gameState.getStatus(i).equals("WIN") ? true: false;
					if(hasWon) gameState.getUser(i).updateWins();
					else gameState.getUser(i).updateLoses();
					
					try {
						// update wins or losses
						GameDataConnectionInterface gameConn = connPool.getConnection();
						gameConn.updateUserStatistics(gameState.getUser(i).getID(), hasWon);
						connPool.returnConnection(gameConn);
						
					} catch (GameException e) {
						
					}
					
					break;
					
				case MULTI:
					// game was interrupted by an error
					numOfConnections--;
					isConnected[1-i] = false;
					monitor.setNotified(1-i, DisconnectionType.NONE);
					threads[1-i].interrupt(); // no break on purpose
					threads[1-i] = null;
				case SINGLE:
					
					numOfConnections--;
					isConnected[i] = false;
					monitor.setNotified(i, DisconnectionType.NONE);
					threads[i] = null;
					disconnect = true;
					break;
					
				}
			}
			if(disconnections == 2){
				break;
			}
			if (disconnect)
				break;
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
			
			}
		}
	}

	public void runServer() {
		
		for (int i = 0; i < threads.length; i++) {
			threads[i] = null;
			isConnected[i] = false;
		}
		
		try {
			serverSocket = new ServerSocket(portNumber);
			connPool = ConnectionPool.getInstance();
		} catch (IOException e) {
			System.err.println("could not connect to socket 3000");
			System.exit(0);
		} catch (GameException e) {
			try {
				serverSocket.close();
			} catch (IOException e1) {
				System.exit(0);
			}
			System.exit(0);
		}
		
		while (true) {
			// wait for connections...
			try {
				while (numOfConnections < 2) {		
				
					int nextConnection = isConnected[0] ? 1 : 0;
					Socket clientSocket = serverSocket.accept();
					threads[nextConnection] = new Thread(
							new ClientConnection(clientSocket,
									gameState, nextConnection, monitor));
					threads[nextConnection].start();
					isConnected[nextConnection] = true;
					numOfConnections++;
			
				}
				
			} catch (IOException e) {
				System.err
						.println("IO exception while creating connection with clients");
				try {
					serverSocket.close();
				} catch (IOException e1) {
						System.exit(0);
				}
				System.exit(0);
			} 
				
			waitForDisconnection();

		}

	}

	public static void main(String[] args) {
		
		DBManager.DB_CONNECTION_STRING = args[0];
		DBManager.DB_USER_NAME = args[1];
		DBManager.DB_PASSWORD = args[2];
		
		ConnectionPool.numberOfConnections = Integer.parseInt(args[3]);
		Server.portNumber = Integer.parseInt(args[4]);
		Server.numCards = Integer.parseInt(args[5]);
		
		Server server = new Server();
		server.runServer();
	}
}